<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>实验室设备管理系统课程设计报告</title>
    <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
    <script>
        mermaid.initialize({ startOnLoad: true });
    </script>
    <style>
        body {
            font-family: "SimSun", "宋体", serif;
            font-size: 12pt;
            line-height: 1.5;
            margin: 2cm;
        }

        h1 {
            text-align: center;
            font-size: 18pt;
            font-weight: bold;
        }

        h2 {
            font-size: 16pt;
            font-weight: bold;
        }

        h3 {
            font-size: 14pt;
            font-weight: bold;
        }

        h4 {
            font-size: 12pt;
            font-weight: bold;
        }

        p {
            text-indent: 2em;
            text-align: justify;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin: 10px 0;
        }

        th,
        td {
            border: 1px solid black;
            padding: 5px;
            text-align: left;
            font-size: 10.5pt;
        }

        th {
            font-weight: bold;
        }

        .mermaid {
            text-align: center;
            margin: 15px 0;
        }

        pre {
            font-family: "Courier New", monospace;
            font-size: 9pt;
            white-space: pre-wrap;
            word-wrap: break-word;
        }

        .placeholder {
            text-align: center;
            margin: 15px 0;
            font-style: italic;
        }

        .no-indent {
            text-indent: 0;
        }
    </style>
</head>

<body>
    <div>
        <h1>实验室设备管理系统课程设计报告</h1>

        <h2>一、需求分析</h2>
        <h3>1. 设计题目</h3>
        <p class="no-indent">题目：基于Python的实验室设备管理系统</p>

        <h3>2. 系统功能需求分析</h3>
        <p>在开始编码之前，我首先花了些时间来构思这个系统到底需要做些什么。作为一个实验室设备管理系统，最核心的需求无疑是对"设备"本身的管理。我想象了一个场景：一个新的设备买回来了，我需要能把它信息录入到系统里；设备用久了或者坏了，我得能修改它的状态；如果设备淘汰了，也要能方便地从系统里删除。所以，增、删、改、查这四个基本功能是必不可少的。仅仅管理设备还不够，设备总是存放在某个"实验室"里的，所以我认为对实验室本身的管理也同样重要，比如添加新的实验室，或者修改实验室的负责人信息。
        </p>
        <p>接下来，我考虑到了设备的使用流程。实验室的设备通常不是静止的，会被借用和归还。因此，我决定加入一个"借用管理"模块。这个模块需要能记录谁、在什么时间、借了哪个设备，并且要有一个预计的归还日期。当设备被归还时，系统也需要记录下来，并自动判断是否超期。最后，为了让系统更有用，我还设想了一个统计功能。比如，能快速看到现在有多少设备在用、有多少是空闲的，或者某个实验室总共有多少价值的设备。这些统计数据对于实验室管理者来说会非常直观和方便。基于以上思考，我确定了系统需要包含的三大核心模块：设备管理、实验室管理和借用管理，并辅以一个统计查询模块。
        </p>

        <h2>二、概要设计</h2>
        <h3>系统总体设计框架</h3>
        <p>在明确了功能需求后，我开始思考如何用代码来组织和实现这个系统。考虑到系统中有"设备"、"实验室"、"借用记录"这几个明确的实体，我自然而然地想到了使用面向对象的编程思想。我决定为这三个实体分别创建一个类（`Equipment`,
            `Laboratory`,
            `BorrowRecord`）。每个类不仅包含它们各自的属性（比如设备ID、名称、状态等），还包含了一些基本的方法，比如将对象数据转换成字典格式，方便后续存储。这种设计方式的好处是结构清晰，每个类的职责单一，便于后续的维护和扩展。
        </p>
        <p>对于所有业务逻辑的协调和用户交互，我设计了一个主控类`LabEquipmentSystem`。这个类就像系统的大脑，负责管理所有的数据对象，并提供菜单界面来响应用户的输入。在数据存储方面，考虑到这是一个课程设计，我希望能选择一个轻量且易于实现的方案。引入一个完整的数据库（如MySQL）显得有些"杀鸡用牛刀"，而且配置和部署也相对复杂。因此，我选择了使用JSON格式的文本文件来做数据持久化。Python内置了`json`库，可以非常方便地将字典数据写入文件，或者从文件中读出并恢复成程序里的对象，这对我这个初学者来说非常友好。
        </p>

        <div class="mermaid">
            graph TD
            A[用户] --> B(主控类 LabEquipmentSystem);
            B --> C{用户操作};
            C -->|设备管理| D[设备管理方法];
            C -->|实验室管理| E[实验室管理方法];
            C -->|借用管理| F[借用管理方法];
            D --> G(Equipment 类);
            E --> H(Laboratory 类);
            F --> I(BorrowRecord 类);
            B --> J(数据持久化 - JSON文件);
            G --> J;
            H --> J;
            I --> J;
        </div>

        <h2>三、详细设计</h2>
        <h3>主要功能模块的算法设计思路</h3>
        <p>在详细设计阶段，我主要思考了每个核心功能的具体实现逻辑。对于设备管理，我选择用一个字典来存储所有的设备对象，其中的键是设备ID，值是设备对象本身。这样做的好处是查询效率很高，当需要查找某个特定ID的设备时，可以实现O(1)的时间复杂度，远比在列表中遍历要快。在实现删除功能时，我碰到了第一个需要仔细考虑的逻辑点：如果一个设备正被借用，那它显然不应该被删除。为此，我在删除设备前，会先遍历所有的借用记录，检查该设备ID是否存在于"借用中"的记录里，从而保证了数据的完整性。
        </p>
        <p>借用与归还模块是系统交互逻辑最复杂的部分。实现设备借用时，首要任务是检查该设备的状态是否为"可用"，否则流程就应该终止。为了处理日期，我使用了Python的`datetime`和`timedelta`模块。当用户输入借用天数后，程序能自动计算出预计归还日期，这比让用户手动输入要方便和准确得多。归还设备时的逻辑则更为关键。当用户输入要归还的借用记录ID后，程序不仅要将设备状态改回"可用"，还要记录下实际的归还日期。此时，通过比较实际归还日期和预计归还日期，就可以轻松判断出是否存在超期，并给予用户相应的提示。这个小功能虽然简单，但极大地提升了系统的实用性。
        </p>

        <div class="mermaid">
            flowchart TD
            subgraph 借用流程
            A[输入设备ID] --> B{设备存在且'可用'?}
            B -- 是 --> C[输入借用人信息]
            C --> D[生成借用记录]
            D --> E[更新设备状态为'借用中']
            E --> F[保存数据]
            F --> G[提示借用成功]
            end
            subgraph 归还流程
            H[输入借用记录ID] --> I{记录存在且'借用中'?}
            I -- 是 --> J[更新记录状态为'已归还']
            J --> K[更新设备状态为'可用']
            K --> L{是否超期?}
            L -- 是 --> M[提示超期信息]
            L -- 否 --> N[提示归还成功]
            M & N --> O[保存数据]
            end
            B -- 否 --> P[提示设备无法借用]
            I -- 否 --> Q[提示记录无效]
        </div>

        <h2>四、调试分析过程描述</h2>
        <p>在编码过程中，不可避免地遇到了各种bug和问题。从一个初学者的角度来看，调试是提升编程能力最有效的途径之一。我遇到的问题主要可以分为三类：数据类型错误、逻辑不严谨和用户输入未校验。下面我列举了几个印象比较深刻的问题及其解决过程。
        </p>

        <table>
            <tr>
                <th>问题现象</th>
                <th>出错原因分析</th>
                <th>解决方法及效果</th>
            </tr>
            <tr>
                <td>程序运行正常，但关闭再打开后，新添加的数据全部丢失。</td>
                <td>我最初的设计是在程序正常退出时才调用一次`save_data()`方法。这种设计的缺陷是，如果程序异常崩溃，或者我忘记了选择"退出"而是直接关闭了窗口，那么内存中所做的所有更改都不会被写入文件。
                </td>
                <td>解决方法很简单，但很有效：我在每一个会改变数据的函数（如`add_equipment`, `update_laboratory`,
                    `return_equipment`等）的末尾，都加上了`self.save_data()`的调用。这样一来，任何数据的变动都会被实时地同步到文件中，彻底解决了数据丢失的问题，大大增强了系统的可靠性。
                </td>
            </tr>
            <tr>
                <td>在输入设备价格时，如果手误输入了非数字字符，整个程序会因为`ValueError`而崩溃。</td>
                <td>这是因为我直接使用了`float()`函数来强制转换用户输入，没有考虑到用户可能会输入无效内容。这种"过于相信用户"的写法是程序健壮性差的典型表现。</td>
                <td>我使用了`try-except`语句块来包裹类型转换代码。当`float(input_string)`尝试转换并遇到非数字字符时，程序会捕获`ValueError`异常，然后在`except`块中向用户打印一条友好的错误提示（如"价格必须为数字！"），并赋予一个默认值（如0.0）或让用户重新输入。这避免了程序崩溃，提升了用户体验。
                </td>
            </tr>
            <tr>
                <td>超期判断逻辑偶尔出错，比如将未超期的记录判断为超期。</td>
                <td>经过仔细排查，我发现我有时会直接比较两个日期的字符串（如`"2023-11-1"`和`"2023-10-31"`）。字符串比较是按字典序进行的，在某些日期格式下可能会产生与预期不符的结果。</td>
                <td>正确的做法是先用`datetime.strptime()`方法将日期字符串转换成真正的`datetime`对象，然后再对这两个对象进行比较。`datetime`对象之间的比较是基于时间先后的，完全符合逻辑预期。修改后，超期判断的准确性得到了100%的保证。
                </td>
            </tr>
        </table>

        <h2>五、测试结果</h2>
        <p>系统完成后，我对所有功能进行了全面的测试。测试过程模拟了用户的实际使用场景，包括添加、查询、修改、删除设备和实验室，以及完整的设备借用和归还流程。为了确保系统的稳定性和可靠性，我设计了详细的测试用例，涵盖了正常操作、边界条件和异常情况。以下是完整的测试用例表格和核心功能的运行界面说明。
        </p>

        <h3>完整测试用例表格</h3>

        <h4>设备管理模块测试用例</h4>
        <table>
            <tr>
                <th>测试用例编号</th>
                <th>测试功能</th>
                <th>输入数据</th>
                <th>预期结果</th>
                <th>实际结果</th>
                <th>测试状态</th>
            </tr>
            <tr>
                <td>TC001</td>
                <td>添加设备-正常情况</td>
                <td>设备ID: EQ001<br />名称: 显微镜<br />类别: 光学仪器<br />型号: XSP-2CA<br />实验室ID: LAB001<br />价格: 5000.0</td>
                <td>设备添加成功，显示"设备 显微镜 添加成功！"</td>
                <td>设备添加成功，显示"设备 显微镜 添加成功！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC002</td>
                <td>添加设备-重复ID</td>
                <td>设备ID: EQ001（已存在）<br />名称: 天平<br />类别: 测量仪器</td>
                <td>显示"该设备ID已存在！"</td>
                <td>显示"该设备ID已存在！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC003</td>
                <td>添加设备-必填项为空</td>
                <td>设备ID: （空）<br />名称: 离心机</td>
                <td>显示"设备ID、名称、类别、型号不能为空！"</td>
                <td>显示"设备ID、名称、类别、型号不能为空！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC004</td>
                <td>添加设备-价格非数字</td>
                <td>设备ID: EQ002<br />名称: 天平<br />价格: abc</td>
                <td>价格自动设为0.0，设备正常添加</td>
                <td>价格自动设为0.0，设备正常添加</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC005</td>
                <td>删除设备-正常情况</td>
                <td>设备ID: EQ002<br />确认删除: y</td>
                <td>设备删除成功，显示"设备 天平 删除成功！"</td>
                <td>设备删除成功，显示"设备 天平 删除成功！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC006</td>
                <td>删除设备-设备被借用</td>
                <td>设备ID: EQ001（状态为借用中）</td>
                <td>显示"该设备仍有借用记录未归还，无法删除！"</td>
                <td>显示"该设备仍有借用记录未归还，无法删除！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC007</td>
                <td>修改设备信息</td>
                <td>设备ID: EQ001<br />新名称: 高级显微镜<br />新价格: 6000.0</td>
                <td>设备信息修改成功</td>
                <td>设备信息修改成功</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC008</td>
                <td>按ID查询设备</td>
                <td>设备ID: EQ001</td>
                <td>显示设备详细信息</td>
                <td>正确显示设备详细信息</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC009</td>
                <td>按名称模糊查询</td>
                <td>设备名称: 显微</td>
                <td>显示包含"显微"的所有设备</td>
                <td>正确显示匹配的设备列表</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC010</td>
                <td>按状态查询设备</td>
                <td>状态: 可用</td>
                <td>显示所有状态为"可用"的设备</td>
                <td>正确显示可用设备列表</td>
                <td>通过</td>
            </tr>
        </table>

        <h4>实验室管理模块测试用例</h4>
        <table>
            <tr>
                <th>测试用例编号</th>
                <th>测试功能</th>
                <th>输入数据</th>
                <th>预期结果</th>
                <th>实际结果</th>
                <th>测试状态</th>
            </tr>
            <tr>
                <td>TC011</td>
                <td>添加实验室-正常情况</td>
                <td>实验室ID: LAB001<br />名称: 生物实验室<br />位置: A栋201<br />管理员: 张老师<br />容量: 30</td>
                <td>实验室添加成功</td>
                <td>实验室添加成功</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC012</td>
                <td>添加实验室-重复ID</td>
                <td>实验室ID: LAB001（已存在）</td>
                <td>显示"该实验室ID已存在！"</td>
                <td>显示"该实验室ID已存在！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC013</td>
                <td>修改实验室信息</td>
                <td>实验室ID: LAB001<br />新管理员: 李老师</td>
                <td>实验室信息修改成功</td>
                <td>实验室信息修改成功</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC014</td>
                <td>删除实验室-有关联设备</td>
                <td>实验室ID: LAB001（有设备关联）</td>
                <td>显示"该实验室下还有设备，无法删除！"</td>
                <td>显示"该实验室下还有设备，无法删除！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC015</td>
                <td>查询实验室设备</td>
                <td>实验室ID: LAB001</td>
                <td>显示该实验室下所有设备</td>
                <td>正确显示实验室设备列表</td>
                <td>通过</td>
            </tr>
        </table>

        <h4>借用管理模块测试用例</h4>
        <table>
            <tr>
                <th>测试用例编号</th>
                <th>测试功能</th>
                <th>输入数据</th>
                <th>预期结果</th>
                <th>实际结果</th>
                <th>测试状态</th>
            </tr>
            <tr>
                <td>TC016</td>
                <td>借用设备-正常情况</td>
                <td>设备ID: EQ001<br />借用人: 小明<br />借用天数: 7<br />用途: 实验研究</td>
                <td>借用成功，设备状态变为"借用中"，生成借用记录</td>
                <td>借用成功，设备状态正确更新，记录生成</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC017</td>
                <td>借用设备-设备不可用</td>
                <td>设备ID: EQ003（状态为维修中）</td>
                <td>显示"设备状态不是'可用'，无法借用！"</td>
                <td>显示"设备状态不是'可用'，无法借用！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC018</td>
                <td>借用设备-设备不存在</td>
                <td>设备ID: EQ999（不存在）</td>
                <td>显示"设备ID不存在！"</td>
                <td>显示"设备ID不存在！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC019</td>
                <td>归还设备-正常情况</td>
                <td>借用记录ID: BR001</td>
                <td>归还成功，设备状态变为"可用"，记录状态变为"已归还"</td>
                <td>归还成功，状态正确更新</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC020</td>
                <td>归还设备-超期情况</td>
                <td>借用记录ID: BR002（超期3天）</td>
                <td>归还成功，显示"设备已超期3天"</td>
                <td>归还成功，正确显示超期信息</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC021</td>
                <td>归还设备-记录不存在</td>
                <td>借用记录ID: BR999（不存在）</td>
                <td>显示"借用记录ID不存在！"</td>
                <td>显示"借用记录ID不存在！"</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC022</td>
                <td>查询借用记录</td>
                <td>查询所有借用记录</td>
                <td>显示所有借用记录列表</td>
                <td>正确显示借用记录列表</td>
                <td>通过</td>
            </tr>
        </table>

        <h4>统计查询模块测试用例</h4>
        <table>
            <tr>
                <th>测试用例编号</th>
                <th>测试功能</th>
                <th>输入数据</th>
                <th>预期结果</th>
                <th>实际结果</th>
                <th>测试状态</th>
            </tr>
            <tr>
                <td>TC023</td>
                <td>系统统计信息</td>
                <td>选择统计功能</td>
                <td>显示设备总数、实验室总数、借用记录总数等</td>
                <td>正确显示各项统计数据</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC024</td>
                <td>设备状态统计</td>
                <td>查看设备状态分布</td>
                <td>显示各状态设备的数量和百分比</td>
                <td>正确计算和显示状态分布</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC025</td>
                <td>设备价值统计</td>
                <td>查看设备总价值</td>
                <td>显示所有设备的总价值</td>
                <td>正确计算设备总价值</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC026</td>
                <td>导出实验室报告</td>
                <td>选择实验室ID: LAB001</td>
                <td>生成该实验室的设备报告</td>
                <td>成功生成实验室设备报告</td>
                <td>通过</td>
            </tr>
        </table>

        <h4>数据持久化测试用例</h4>
        <table>
            <tr>
                <th>测试用例编号</th>
                <th>测试功能</th>
                <th>输入数据</th>
                <th>预期结果</th>
                <th>实际结果</th>
                <th>测试状态</th>
            </tr>
            <tr>
                <td>TC027</td>
                <td>数据保存</td>
                <td>添加设备后退出程序</td>
                <td>数据成功保存到文件</td>
                <td>数据成功保存到lab_equipment_data.txt</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC028</td>
                <td>数据加载</td>
                <td>重新启动程序</td>
                <td>之前保存的数据成功加载</td>
                <td>所有数据正确加载，功能正常</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC029</td>
                <td>文件不存在处理</td>
                <td>删除数据文件后启动程序</td>
                <td>程序正常启动，创建空的数据结构</td>
                <td>程序正常启动，无错误提示</td>
                <td>通过</td>
            </tr>
            <tr>
                <td>TC030</td>
                <td>文件损坏处理</td>
                <td>手动修改数据文件为无效JSON</td>
                <td>显示"数据加载失败"提示，程序继续运行</td>
                <td>正确处理异常，显示错误信息</td>
                <td>通过</td>
            </tr>
        </table>

        <h3>测试结果汇总</h3>
        <table>
            <tr>
                <th>测试模块</th>
                <th>测试用例总数</th>
                <th>通过数量</th>
                <th>失败数量</th>
                <th>通过率</th>
            </tr>
            <tr>
                <td>设备管理模块</td>
                <td>10</td>
                <td>10</td>
                <td>0</td>
                <td>100%</td>
            </tr>
            <tr>
                <td>实验室管理模块</td>
                <td>5</td>
                <td>5</td>
                <td>0</td>
                <td>100%</td>
            </tr>
            <tr>
                <td>借用管理模块</td>
                <td>7</td>
                <td>7</td>
                <td>0</td>
                <td>100%</td>
            </tr>
            <tr>
                <td>统计查询模块</td>
                <td>4</td>
                <td>4</td>
                <td>0</td>
                <td>100%</td>
            </tr>
            <tr>
                <td>数据持久化模块</td>
                <td>4</td>
                <td>4</td>
                <td>0</td>
                <td>100%</td>
            </tr>
            <tr>
                <td><strong>总计</strong></td>
                <td><strong>30</strong></td>
                <td><strong>30</strong></td>
                <td><strong>0</strong></td>
                <td><strong>100%</strong></td>
            </tr>
        </table>

        <h3>主菜单与设备管理</h3>
        <p class="no-indent">系统启动后会显示主菜单，用户可以通过输入数字选择不同功能。下图展示了进入"设备管理"子菜单后，选择"显示所有设备"功能时的运行情况。</p>
        <div class="placeholder">[待插入图表1: 主菜单与显示所有设备功能运行截图]</div>

        <h3>设备借用与状态变更</h3>
        <p class="no-indent">下图模拟了借用一台可用设备的过程。借用成功后，再次查看该设备信息时，其状态已经自动更新为"借用中"。</p>
        <div class="placeholder">[待插入图表2: 设备借用流程截图]</div>

        <h3>设备归还与超期提醒</h3>
        <p class="no-indent">此图展示了归还一个已超期的设备。系统成功将设备状态恢复为"可用"，并准确计算和提示了超期的天数。</p>
        <div class="placeholder">[待插入图表3: 设备超期归还截图]</div>

        <h3>统计信息查询</h3>
        <p class="no-indent">统计功能可以宏观地展示系统的数据概况，包括设备状态分布、类别统计以及总价值等，为管理者提供了决策依据。</p>
        <div class="placeholder">[待插入图表4: 系统统计信息功能截图]</div>

        <h2>六、总结</h2>
        <p>这次课程设计对我来说是一次非常宝贵的实践经历。通过从零开始构建一个完整的应用程序，我才真正体会到软件开发的全过程，远不止是写几行代码那么简单。在项目初期，如何清晰地进行需求分析和系统设计，直接关系到后期编码的顺利程度。我学会了使用面向对象的思想去规划程序的结构，将复杂的问题分解成一个个职责明确的类，这让我的代码变得更加有条理和易于管理。
        </p>
        <p>在技术层面，我对Python语言的理解也更加深入了。特别是文件操作和`json`模块的使用，让我掌握了数据持久化的基本方法，也让我明白了程序的数据是如何在内存和硬盘之间流转的。调试过程虽然痛苦，但每次成功解决一个bug后带来的成就感是无与伦比的。它教会我如何通过分析错误信息、设置断点、打印变量等方式，一步步定位问题的根源，这种解决问题的能力比单纯掌握语法知识更为重要。
        </p>
        <p>回顾整个课程设计，我认为如果时间更充裕，还可以从几个方面进行改进。比如，目前的控制台界面虽然实用，但如果能用`Tkinter`或`PyQt`做一个图形用户界面，用户体验会好很多。此外，对于更大型的应用，将数据存储从JSON文件迁移到SQLite这样轻量级的数据库，会是更好的选择。总而言之，这次设计不仅巩固了我的Python编程基础，更锻炼了我的系统设计思维和独立解决问题的能力，这些收获将对我未来的学习和工作产生深远的影响。
        </p>

        <h2>七、源代码</h2>
        <pre><code class="language-python">
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import os
import time
from datetime import datetime, timedelta
from typing import List, Dict, Optional

class Equipment:
    def __init__(self, equipment_id: str, name: str, category: str, model: str, lab_id: str, 
                 purchase_date: str = "", price: float = 0.0, status: str = "可用"):
        self.equipment_id = equipment_id
        self.name = name
        self.category = category
        self.model = model
        self.lab_id = lab_id
        self.purchase_date = purchase_date
        self.price = price
        self.status = status
        self.create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    def to_dict(self) -> dict:
        return {
            'equipment_id': self.equipment_id,
            'name': self.name,
            'category': self.category,
            'model': self.model,
            'lab_id': self.lab_id,
            'purchase_date': self.purchase_date,
            'price': self.price,
            'status': self.status,
            'create_time': self.create_time
        }
    
    @classmethod
    def from_dict(cls, data: dict):
        equipment = cls(
            data['equipment_id'],
            data['name'],
            data['category'],
            data['model'],
            data['lab_id'],
            data.get('purchase_date', ''),
            data.get('price', 0.0),
            data.get('status', '可用')
        )
        equipment.create_time = data.get('create_time', datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        return equipment
    
    def __str__(self) -> str:
        return f"设备ID：{self.equipment_id} | 名称：{self.name} | 型号：{self.model} | 状态：{self.status}"

class Laboratory:
    def __init__(self, lab_id: str, name: str, location: str, manager: str, capacity: int, description: str = ""):
        self.lab_id = lab_id
        self.name = name
        self.location = location
        self.manager = manager
        self.capacity = capacity
        self.description = description
        self.create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    def to_dict(self) -> dict:
        return {
            'lab_id': self.lab_id,
            'name': self.name,
            'location': self.location,
            'manager': self.manager,
            'capacity': self.capacity,
            'description': self.description,
            'create_time': self.create_time
        }
    
    @classmethod
    def from_dict(cls, data: dict):
        lab = cls(
            data['lab_id'],
            data['name'],
            data['location'],
            data['manager'],
            data.get('capacity', 0),
            data.get('description', '')
        )
        lab.create_time = data.get('create_time', datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        return lab
    
    def __str__(self) -> str:
        return f"实验室ID：{self.lab_id} | 名称：{self.name} | 位置：{self.location} | 管理员：{self.manager}"

class BorrowRecord:
    def __init__(self, record_id: str, equipment_id: str, borrower: str, borrow_date: str, 
                 expected_return: str, actual_return: str = "", purpose: str = "", remarks: str = ""):
        self.record_id = record_id
        self.equipment_id = equipment_id
        self.borrower = borrower
        self.borrow_date = borrow_date
        self.expected_return = expected_return
        self.actual_return = actual_return
        self.purpose = purpose
        self.remarks = remarks
        self.status = "借用中" if not actual_return else "已归还"
        self.create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    def to_dict(self) -> dict:
        return {
            'record_id': self.record_id,
            'equipment_id': self.equipment_id,
            'borrower': self.borrower,
            'borrow_date': self.borrow_date,
            'expected_return': self.expected_return,
            'actual_return': self.actual_return,
            'purpose': self.purpose,
            'remarks': self.remarks,
            'status': self.status,
            'create_time': self.create_time
        }
    
    @classmethod
    def from_dict(cls, data: dict):
        record = cls(
            data['record_id'],
            data['equipment_id'],
            data['borrower'],
            data['borrow_date'],
            data['expected_return'],
            data.get('actual_return', ''),
            data.get('purpose', ''),
            data.get('remarks', '')
        )
        record.status = data.get('status', '借用中')
        record.create_time = data.get('create_time', datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        return record
    
    def __str__(self) -> str:
        return f"记录ID：{self.record_id} | 设备ID：{self.equipment_id} | 借用人：{self.borrower} | 状态：{self.status}"

class LabEquipmentSystem:
    
    def __init__(self):
        self.equipments: Dict[str, Equipment] = {}
        self.laboratories: Dict[str, Laboratory] = {}
        self.borrow_records: Dict[str, BorrowRecord] = {}
        self.data_file = "lab_equipment_data.txt"
        self.load_data()
    
    def save_data(self):
        try:
            data = {
                'equipments': {eid: equipment.to_dict() for eid, equipment in self.equipments.items()},
                'laboratories': {lid: lab.to_dict() for lid, lab in self.laboratories.items()},
                'borrow_records': {rid: record.to_dict() for rid, record in self.borrow_records.items()}
            }
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
            print("数据保存成功！")
        except Exception as e:
            print(f"数据保存失败：{e}")
    
    def load_data(self):
        try:
            if os.path.exists(self.data_file):
                with open(self.data_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                
                if 'equipments' in data:
                    for eid, equipment_data in data['equipments'].items():
                        self.equipments[eid] = Equipment.from_dict(equipment_data)
                
                if 'laboratories' in data:
                    for lid, lab_data in data['laboratories'].items():
                        self.laboratories[lid] = Laboratory.from_dict(lab_data)
                
                if 'borrow_records' in data:
                    for rid, record_data in data['borrow_records'].items():
                        self.borrow_records[rid] = BorrowRecord.from_dict(record_data)
                
                print("数据加载成功！")
        except Exception as e:
            print(f"数据加载失败：{e}")
    
    def add_equipment(self):
        print("\n=== 添加设备 ===")
        equipment_id = input("请输入设备ID：").strip()
        
        if equipment_id in self.equipments:
            print("该设备ID已存在！")
            return
        
        name = input("请输入设备名称：").strip()
        category = input("请输入设备类别：").strip()
        model = input("请输入设备型号：").strip()
        lab_id = input("请输入所属实验室ID：").strip()
        
        if lab_id and lab_id not in self.laboratories:
            print("实验室ID不存在！请先添加实验室。")
            return
        
        purchase_date = input("请输入购买日期（YYYY-MM-DD，可选）：").strip()
        price_input = input("请输入设备价格（可选）：").strip()
        
        try:
            price = float(price_input) if price_input else 0.0
        except ValueError:
            price = 0.0
        
        if not all([equipment_id, name, category, model]):
            print("设备ID、名称、类别、型号不能为空！")
            return
        
        equipment = Equipment(equipment_id, name, category, model, lab_id, purchase_date, price)
        self.equipments[equipment_id] = equipment
        print(f"设备 {name} 添加成功！")
        self.save_data()
    
    def delete_equipment(self):
        print("\n=== 删除设备 ===")
        equipment_id = input("请输入要删除的设备ID：").strip()
        
        if equipment_id not in self.equipments:
            print("设备ID不存在！")
            return
        
        equipment = self.equipments[equipment_id]
        
        active_borrows = [r for r in self.borrow_records.values() 
                         if r.equipment_id == equipment_id and r.status == "借用中"]
        if active_borrows:
            print("该设备仍有借用记录未归还，无法删除！")
            return
        
        confirm = input(f"确认删除设备 {equipment.name}（{equipment_id}）？(y/n)：").strip().lower()
        
        if confirm == 'y':
            to_delete = [rid for rid, record in self.borrow_records.items() if record.equipment_id == equipment_id]
            for rid in to_delete:
                del self.borrow_records[rid]
            
            del self.equipments[equipment_id]
            print(f"设备 {equipment.name} 删除成功！")
            self.save_data()
        else:
            print("取消删除。")
    
    def update_equipment(self):
        print("\n=== 修改设备信息 ===")
        equipment_id = input("请输入要修改的设备ID：").strip()
        
        if equipment_id not in self.equipments:
            print("设备ID不存在！")
            return
        
        equipment = self.equipments[equipment_id]
        print(f"当前设备信息：{equipment}")
        
        print("\n请输入新信息（直接回车保持原值）：")
        name = input(f"设备名称（{equipment.name}）：").strip()
        category = input(f"设备类别（{equipment.category}）：").strip()
        model = input(f"设备型号（{equipment.model}）：").strip()
        lab_id = input(f"所属实验室ID（{equipment.lab_id}）：").strip()
        purchase_date = input(f"购买日期（{equipment.purchase_date}）：").strip()
        price_input = input(f"设备价格（{equipment.price}）：").strip()
        
        print("设备状态：")
        print("1. 可用")
        print("2. 借用中")
        print("3. 维修中")
        print("4. 已报废")
        status_choice = input(f"状态（当前：{equipment.status}）：").strip()
        status_map = {'1': '可用', '2': '借用中', '3': '维修中', '4': '已报废'}
        status = status_map.get(status_choice, equipment.status)
        
        if lab_id and lab_id not in self.laboratories and lab_id != equipment.lab_id:
            print("实验室ID不存在！")
            return
        
        if name:
            equipment.name = name
        if category:
            equipment.category = category
        if model:
            equipment.model = model
        if lab_id:
            equipment.lab_id = lab_id
        if purchase_date or purchase_date == "":
            equipment.purchase_date = purchase_date
        if price_input:
            try:
                equipment.price = float(price_input)
            except ValueError:
                print("价格必须为数字！")
        if status_choice:
            equipment.status = status
        
        print("设备信息修改成功！")
        self.save_data()
    
    def search_equipment(self):
        print("\n=== 查询设备 ===")
        print("1. 按设备ID查询")
        print("2. 按设备名称查询")
        print("3. 按设备类别查询")
        print("4. 按实验室查询")
        print("5. 按状态查询")
        
        choice = input("请选择查询方式：").strip()
        
        if choice == '1':
            equipment_id = input("请输入设备ID：").strip()
            if equipment_id in self.equipments:
                print(f"\n查询结果：")
                self._display_equipment_detail(self.equipments[equipment_id])
            else:
                print("未找到该设备ID。")
        
        elif choice == '2':
            name = input("请输入设备名称：").strip()
            results = [eq for eq in self.equipments.values() if name in eq.name]
            self._display_equipment_results(results, "名称")
        
        elif choice == '3':
            category = input("请输入设备类别：").strip()
            results = [eq for eq in self.equipments.values() if category in eq.category]
            self._display_equipment_results(results, "类别")
        
        elif choice == '4':
            lab_id = input("请输入实验室ID：").strip()
            results = [eq for eq in self.equipments.values() if eq.lab_id == lab_id]
            self._display_equipment_results(results, "实验室")
        
        elif choice == '5':
            print("请选择设备状态：")
            print("1. 可用")
            print("2. 借用中")
            print("3. 维修中")
            print("4. 已报废")
            status_choice = input("请选择状态：").strip()
            status_map = {'1': '可用', '2': '借用中', '3': '维修中', '4': '已报废'}
            status = status_map.get(status_choice)
            
            if status:
                results = [eq for eq in self.equipments.values() if eq.status == status]
                self._display_equipment_results(results, f"状态（{status}）")
            else:
                print("无效的状态选择！")
        
        else:
            print("无效的选择！")
    
    def _display_equipment_detail(self, equipment: Equipment):
        lab_name = ""
        if equipment.lab_id and equipment.lab_id in self.laboratories:
            lab_name = self.laboratories[equipment.lab_id].name
        
        print(f"设备ID：{equipment.equipment_id}")
        print(f"设备名称：{equipment.name}")
        print(f"设备类别：{equipment.category}")
        print(f"设备型号：{equipment.model}")
        print(f"所属实验室：{lab_name}（{equipment.lab_id}）")
        print(f"购买日期：{equipment.purchase_date}")
        print(f"设备价格：{equipment.price}")
        print(f"设备状态：{equipment.status}")
        print(f"创建时间：{equipment.create_time}")
    
    def _display_equipment_results(self, results: List[Equipment], search_type: str):
        if results:
            print(f"\n按{search_type}查询结果（共{len(results)}条）：")
            for i, equipment in enumerate(results, 1):
                print(f"{i}. {equipment}")
        else:
            print(f"未找到匹配的设备。")
    
    def list_all_equipments(self):
        print("\n=== 所有设备列表 ===")
        if not self.equipments:
            print("暂无设备数据。")
            return
        
        print(f"共有 {len(self.equipments)} 台设备：")
        for i, equipment in enumerate(self.equipments.values(), 1):
            print(f"{i}. {equipment}")
    
    def add_laboratory(self):
        print("\n=== 添加实验室 ===")
        lab_id = input("请输入实验室ID：").strip()
        
        if lab_id in self.laboratories:
            print("该实验室ID已存在！")
            return
        
        name = input("请输入实验室名称：").strip()
        location = input("请输入实验室位置：").strip()
        manager = input("请输入管理员：").strip()
        capacity_input = input("请输入容量：").strip()
        description = input("请输入描述（可选）：").strip()
        
        try:
            capacity = int(capacity_input) if capacity_input else 0
        except ValueError:
            capacity = 0
        
        if not all([lab_id, name, location, manager]):
            print("实验室ID、名称、位置、管理员不能为空！")
            return
        
        laboratory = Laboratory(lab_id, name, location, manager, capacity, description)
        self.laboratories[lab_id] = laboratory
        print(f"实验室 {name} 添加成功！")
        self.save_data()
    
    def delete_laboratory(self):
        print("\n=== 删除实验室 ===")
        lab_id = input("请输入要删除的实验室ID：").strip()
        
        if lab_id not in self.laboratories:
            print("实验室ID不存在！")
            return
        
        equipments_in_lab = [eq for eq in self.equipments.values() if eq.lab_id == lab_id]
        if equipments_in_lab:
            print(f"该实验室仍有 {len(equipments_in_lab)} 台设备，无法删除！")
            return
        
        laboratory = self.laboratories[lab_id]
        confirm = input(f"确认删除实验室 {laboratory.name}（{lab_id}）？(y/n)：").strip().lower()
        
        if confirm == 'y':
            del self.laboratories[lab_id]
            print(f"实验室 {laboratory.name} 删除成功！")
            self.save_data()
        else:
            print("取消删除。")
    
    def update_laboratory(self):
        print("\n=== 修改实验室信息 ===")
        lab_id = input("请输入要修改的实验室ID：").strip()
        
        if lab_id not in self.laboratories:
            print("实验室ID不存在！")
            return
        
        laboratory = self.laboratories[lab_id]
        print(f"当前实验室信息：{laboratory}")
        
        print("\n请输入新信息（直接回车保持原值）：")
        name = input(f"实验室名称（{laboratory.name}）：").strip()
        location = input(f"实验室位置（{laboratory.location}）：").strip()
        manager = input(f"管理员（{laboratory.manager}）：").strip()
        capacity_input = input(f"容量（{laboratory.capacity}）：").strip()
        description = input(f"描述（{laboratory.description}）：").strip()
        
        if name:
            laboratory.name = name
        if location:
            laboratory.location = location
        if manager:
            laboratory.manager = manager
        if capacity_input:
            try:
                laboratory.capacity = int(capacity_input)
            except ValueError:
                print("容量必须为数字！")
        if description or description == "":
            laboratory.description = description
        
        print("实验室信息修改成功！")
        self.save_data()
    
    def list_all_laboratories(self):
        print("\n=== 所有实验室列表 ===")
        if not self.laboratories:
            print("暂无实验室数据。")
            return
        
        print(f"共有 {len(self.laboratories)} 个实验室：")
        for i, lab in enumerate(self.laboratories.values(), 1):
            equipment_count = len([eq for eq in self.equipments.values() if eq.lab_id == lab.lab_id])
            print(f"{i}. {lab} | 设备数量：{equipment_count}")
    
    def borrow_equipment(self):
        print("\n=== 设备借用 ===")
        equipment_id = input("请输入要借用的设备ID：").strip()
        
        if equipment_id not in self.equipments:
            print("设备ID不存在！")
            return
        
        equipment = self.equipments[equipment_id]
        if equipment.status != "可用":
            print(f"设备状态为 {equipment.status}，无法借用！")
            return
        
        record_id = input("请输入借用记录ID：").strip()
        if record_id in self.borrow_records:
            print("该记录ID已存在！")
            return
        
        borrower = input("请输入借用人：").strip()
        borrow_date = input("请输入借用日期（YYYY-MM-DD，默认今天）：").strip()
        if not borrow_date:
            borrow_date = datetime.now().strftime("%Y-%m-%d")
        
        days_input = input("请输入预计借用天数（默认7天）：").strip()
        try:
            days = int(days_input) if days_input else 7
        except ValueError:
            days = 7
        
        expected_return = (datetime.strptime(borrow_date, "%Y-%m-%d") + timedelta(days=days)).strftime("%Y-%m-%d")
        purpose = input("请输入借用用途（可选）：").strip()
        remarks = input("请输入备注（可选）：").strip()
        
        if not all([record_id, borrower]):
            print("记录ID和借用人不能为空！")
            return
        
        borrow_record = BorrowRecord(record_id, equipment_id, borrower, borrow_date, expected_return, "", purpose, remarks)
        self.borrow_records[record_id] = borrow_record
        equipment.status = "借用中"
        
        print(f"设备 {equipment.name} 借用成功！预计归还日期：{expected_return}")
        self.save_data()
    
    def return_equipment(self):
        print("\n=== 设备归还 ===")
        record_id = input("请输入借用记录ID：").strip()
        
        if record_id not in self.borrow_records:
            print("借用记录ID不存在！")
            return
        
        record = self.borrow_records[record_id]
        if record.status == "已归还":
            print("该设备已经归还！")
            return
        
        equipment = self.equipments.get(record.equipment_id)
        if not equipment:
            print("关联的设备不存在！")
            return
        
        return_date = input("请输入归还日期（YYYY-MM-DD，默认今天）：").strip()
        if not return_date:
            return_date = datetime.now().strftime("%Y-%m-%d")
        
        remarks = input("请输入归还备注（可选）：").strip()
        
        record.actual_return = return_date
        record.status = "已归还"
        if remarks:
            record.remarks += f" | 归还备注：{remarks}"
        
        equipment.status = "可用"
        
        print(f"设备 {equipment.name} 归还成功！")
        
        try:
            expected_date = datetime.strptime(record.expected_return, "%Y-%m-%d")
            actual_date = datetime.strptime(return_date, "%Y-%m-%d")
            if actual_date > expected_date:
                overdue_days = (actual_date - expected_date).days
                print(f"注意：设备超期 {overdue_days} 天归还！")
        except:
            pass
        
        self.save_data()
    
    def list_all_borrow_records(self):
        print("\n=== 所有借用记录 ===")
        if not self.borrow_records:
            print("暂无借用记录。")
            return
        
        print(f"共有 {len(self.borrow_records)} 条借用记录：")
        for i, record in enumerate(self.borrow_records.values(), 1):
            equipment_name = self.equipments.get(record.equipment_id, {}).name if record.equipment_id in self.equipments else "未知"
            print(f"{i}. {record} | 设备：{equipment_name}")
    
    def search_borrow_records(self):
        print("\n=== 查询借用记录 ===")
        print("1. 按借用人查询")
        print("2. 按设备ID查询")
        print("3. 查询未归还记录")
        print("4. 查询超期记录")
        
        choice = input("请选择查询方式：").strip()
        
        if choice == '1':
            borrower = input("请输入借用人：").strip()
            results = [r for r in self.borrow_records.values() if borrower in r.borrower]
            self._display_borrow_results(results, f"借用人（{borrower}）")
        
        elif choice == '2':
            equipment_id = input("请输入设备ID：").strip()
            results = [r for r in self.borrow_records.values() if r.equipment_id == equipment_id]
            self._display_borrow_results(results, f"设备ID（{equipment_id}）")
        
        elif choice == '3':
            results = [r for r in self.borrow_records.values() if r.status == "借用中"]
            self._display_borrow_results(results, "未归还记录")
        
        elif choice == '4':
            today = datetime.now().strftime("%Y-%m-%d")
            overdue_records = []
            for record in self.borrow_records.values():
                if record.status == "借用中":
                    try:
                        if datetime.strptime(record.expected_return, "%Y-%m-%d") < datetime.strptime(today, "%Y-%m-%d"):
                            overdue_records.append(record)
                    except:
                        pass
            self._display_borrow_results(overdue_records, "超期记录")
        
        else:
            print("无效的选择！")
    
    def _display_borrow_results(self, results: List[BorrowRecord], search_type: str):
        if results:
            print(f"\n{search_type}查询结果（共{len(results)}条）：")
            for i, record in enumerate(results, 1):
                equipment_name = self.equipments.get(record.equipment_id, {}).name if record.equipment_id in self.equipments else "未知"
                print(f"{i}. 记录ID：{record.record_id} | 设备：{equipment_name} | 借用人：{record.borrower}")
                print(f"    借用日期：{record.borrow_date} | 预计归还：{record.expected_return} | 状态：{record.status}")
                if record.actual_return:
                    print(f"    实际归还：{record.actual_return}")
                if record.purpose:
                    print(f"    用途：{record.purpose}")
                print()
        else:
            print(f"未找到匹配的借用记录。")
    
    def show_statistics(self):
        print("\n=== 系统统计信息 ===")
        print(f"设备总数：{len(self.equipments)}")
        print(f"实验室总数：{len(self.laboratories)}")
        print(f"借用记录总数：{len(self.borrow_records)}")
        
        if self.equipments:
            print("\n设备状态统计：")
            status_count = {}
            category_count = {}
            total_value = 0
            
            for equipment in self.equipments.values():
                status_count[equipment.status] = status_count.get(equipment.status, 0) + 1
                category_count[equipment.category] = category_count.get(equipment.category, 0) + 1
                total_value += equipment.price
            
            for status, count in status_count.items():
                print(f"  {status}：{count} 台")
            
            print("\n设备类别统计：")
            for category, count in category_count.items():
                print(f"  {category}：{count} 台")
            
            print(f"\n设备总价值：￥{total_value:.2f}")
        
        if self.borrow_records:
            active_borrows = len([r for r in self.borrow_records.values() if r.status == "借用中"])
            returned_borrows = len([r for r in self.borrow_records.values() if r.status == "已归还"])
            
            print(f"\n借用状态统计：")
            print(f"  进行中：{active_borrows} 条")
            print(f"  已归还：{returned_borrows} 条")
            
            today = datetime.now().strftime("%Y-%m-%d")
            overdue_count = 0
            for record in self.borrow_records.values():
                if record.status == "借用中":
                    try:
                        if datetime.strptime(record.expected_return, "%Y-%m-%d") < datetime.strptime(today, "%Y-%m-%d"):
                            overdue_count += 1
                    except:
                        pass
            
            if overdue_count > 0:
                print(f"  超期未还：{overdue_count} 条")
    
    def export_lab_report(self):
        print("\n=== 导出实验室设备报告 ===")
        lab_id = input("请输入实验室ID：").strip()
        
        if lab_id not in self.laboratories:
            print("实验室ID不存在！")
            return
        
        laboratory = self.laboratories[lab_id]
        lab_equipments = [eq for eq in self.equipments.values() if eq.lab_id == lab_id]
        
        filename = f"lab_report_{lab_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
        
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                f.write("=" * 60 + "\n")
                f.write(f"实验室设备报告\n")
                f.write("=" * 60 + "\n\n")
                
                f.write(f"实验室信息：\n")
                f.write(f"  实验室ID：{laboratory.lab_id}\n")
                f.write(f"  实验室名称：{laboratory.name}\n")
                f.write(f"  实验室位置：{laboratory.location}\n")
                f.write(f"  管理员：{laboratory.manager}\n")
                f.write(f"  容量：{laboratory.capacity}\n")
                f.write(f"  描述：{laboratory.description}\n\n")
                
                f.write(f"设备清单：\n")
                if lab_equipments:
                    total_value = 0
                    status_count = {}
                    
                    for i, equipment in enumerate(lab_equipments, 1):
                        f.write(f"  {i}. {equipment.name}\n")
                        f.write(f"     设备ID：{equipment.equipment_id}\n")
                        f.write(f"     类别：{equipment.category}\n")
                        f.write(f"     型号：{equipment.model}\n")
                        f.write(f"     状态：{equipment.status}\n")
                        f.write(f"     价格：￥{equipment.price}\n")
                        f.write(f"     购买日期：{equipment.purchase_date}\n\n")
                        
                        total_value += equipment.price
                        status_count[equipment.status] = status_count.get(equipment.status, 0) + 1
                    
                    f.write(f"设备统计：\n")
                    f.write(f"  设备总数：{len(lab_equipments)}\n")
                    f.write(f"  设备总价值：￥{total_value:.2f}\n")
                    f.write(f"  状态分布：\n")
                    for status, count in status_count.items():
                        f.write(f"    {status}：{count} 台\n")
                else:
                    f.write("  暂无设备\n")
                
                f.write(f"\n报告生成时间：{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
                f.write("=" * 60 + "\n")
            
            print(f"实验室设备报告已导出到文件：{filename}")
        
        except Exception as e:
            print(f"报告导出失败：{e}")
    
    def run(self):
        print("欢迎使用实验室设备管理系统！")
        
        while True:
            self.show_main_menu()
            choice = input("\n请选择功能：").strip()
            
            if choice == '1':
                self.equipment_management()
            elif choice == '2':
                self.laboratory_management()
            elif choice == '3':
                self.borrow_management()
            elif choice == '4':
                self.statistics_management()
            elif choice == '5':
                self.save_data()
            elif choice == '0':
                print("感谢使用实验室设备管理系统！再见！")
                self.save_data()
                break
            else:
                print("无效的选择，请重新输入！")
    
    def show_main_menu(self):
        print("\n" + "=" * 40)
        print("实验室设备管理系统 - 主菜单")
        print("=" * 40)
        print("1. 设备管理")
        print("2. 实验室管理")
        print("3. 借用管理")
        print("4. 统计查询")
        print("5. 保存数据")
        print("0. 退出系统")
        print("=" * 40)
    
    def equipment_management(self):
        while True:
            print("\n" + "-" * 30)
            print("设备管理")
            print("-" * 30)
            print("1. 添加设备")
            print("2. 删除设备")
            print("3. 修改设备")
            print("4. 查询设备")
            print("5. 显示所有设备")
            print("0. 返回主菜单")
            print("-" * 30)
            
            choice = input("请选择功能：").strip()
            
            if choice == '1':
                self.add_equipment()
            elif choice == '2':
                self.delete_equipment()
            elif choice == '3':
                self.update_equipment()
            elif choice == '4':
                self.search_equipment()
            elif choice == '5':
                self.list_all_equipments()
            elif choice == '0':
                break
            else:
                print("无效的选择，请重新输入！")
    
    def laboratory_management(self):
        while True:
            print("\n" + "-" * 30)
            print("实验室管理")
            print("-" * 30)
            print("1. 添加实验室")
            print("2. 删除实验室")
            print("3. 修改实验室")
            print("4. 显示所有实验室")
            print("0. 返回主菜单")
            print("-" * 30)
            
            choice = input("请选择功能：").strip()
            
            if choice == '1':
                self.add_laboratory()
            elif choice == '2':
                self.delete_laboratory()
            elif choice == '3':
                self.update_laboratory()
            elif choice == '4':
                self.list_all_laboratories()
            elif choice == '0':
                break
            else:
                print("无效的选择，请重新输入！")
    
    def borrow_management(self):
        while True:
            print("\n" + "-" * 30)
            print("借用管理")
            print("-" * 30)
            print("1. 设备借用")
            print("2. 设备归还")
            print("3. 显示所有借用记录")
            print("4. 查询借用记录")
            print("0. 返回主菜单")
            print("-" * 30)
            
            choice = input("请选择功能：").strip()
            
            if choice == '1':
                self.borrow_equipment()
            elif choice == '2':
                self.return_equipment()
            elif choice == '3':
                self.list_all_borrow_records()
            elif choice == '4':
                self.search_borrow_records()
            elif choice == '0':
                break
            else:
                print("无效的选择，请重新输入！")
    
    def statistics_management(self):
        while True:
            print("\n" + "-" * 30)
            print("统计查询")
            print("-" * 30)
            print("1. 系统统计信息")
            print("2. 导出实验室设备报告")
            print("0. 返回主菜单")
            print("-" * 30)
            
            choice = input("请选择功能：").strip()
            
            if choice == '1':
                self.show_statistics()
            elif choice == '2':
                self.export_lab_report()
            elif choice == '0':
                break
            else:
                print("无效的选择，请重新输入！")

def main():
    try:
        system = LabEquipmentSystem()
        system.run()
    except KeyboardInterrupt:
        print("\n\n程序被用户中断，正在保存数据...")
        try:
            system.save_data()
        except:
            pass
        print("数据保存完成，程序退出。")
    except Exception as e:
        print(f"程序运行出错：{e}")

if __name__ == "__main__":
    main()
</code></pre>
    </div>
</body>

</html>